#ifndef _BUILD_DFA_TREE_LOC
#define _BUILD_DFA_TREE_LOC

#include "Build_dfa_tree_loc.h"

using namespace build_dfa_tree_loc;


#include "Algorithm.h"
#include <climits>
namespace get_set_loc {
	const bool OK=false;
	const bool ERROR=true;
	const int ERR = INT_MIN, ACC = INT_MAX;
	int actions[10][3] = {
		3, 4, ERR, 
		ERR, ERR, ACC, 
		9, 4, -3, 
		ERR, 4, ERR, 
		5, -5, -5, 
		ERR, 6, ERR, 
		-6, -6, -6, 
		ERR, 4, -1, 
		-4, -4, -4, 
		ERR, ERR, -2 
	};
	int gotos[10][2] = {
		1, 2, 
		ERR, ERR, 
		ERR, 8, 
		ERR, 7, 
		ERR, ERR, 
		ERR, ERR, 
		ERR, ERR, 
		ERR, 8, 
		ERR, 8, 
		ERR, ERR
	};
	enum set_token_id { MINUS, CHAR, END, END_LINE, UNDEF };
	enum { S_s=1, Ss_, Ss, sss, sc, sc_c };
	enum { Set, set };
	class Token {
	public:
		Token(mylib::Buffer &i) : in(i) { c = 0; }
		~Token() {}
		set_token_id get() {
			if( !in.get(c) )		// goto the end
				return END_LINE;
			switch(c) {
			case '-' :			// Minus
				return MINUS;
			case '\n' :
				return END_LINE;
			case ']' :
				in.ret();
				return END;
			case '\\' :			// escape character
				mylib::get_escape_char(in, c);
				return CHAR;
			default :
				return CHAR;
			}
		}
		char token(){ return c;}
	private:
		mylib::Buffer &in;
		char c;
	};
}
#include <stack>
bool build_dfa_tree_loc::get_set(mylib::Buffer &in, mylib::Set<char> &s) {	// 1 label error
	using namespace std;
	using namespace get_set_loc;
	Token token(in);	// buffer
	bool err = false;
	stack<int> states;
	stack<char> chars;
	set_token_id token_id = token.get();
	states.push(0);
	for(; ;) {
		int cur_state = states.top();
		if( token_id == get_set_loc::UNDEF ) {
			err = true;
			break;
		} else if( token_id == get_set_loc::END_LINE ) {
			err = true;
			in.ret();
			s.clear();
			return ERROR;
		}
		int action = actions[cur_state][token_id];
		if( action == get_set_loc::ACC )
			break;
		else if( action == ERR ) {
			err = true;
			break;
		} else if( action >= 0 ) {	// shift
			if( token_id == get_set_loc::CHAR )		// save the character
				chars.push(token.token());
			states.push(action);
			token_id = token.get();
		} else if( action < 0 ) {
			int red_num = -action;
			int red_var;
			int del_state_num=0;
			switch(red_num) {
			case get_set_loc::S_s: case get_set_loc::Ss_ :		// Set : - set || // Set : set -
				s += '-';
				red_var = get_set_loc::Set;
				del_state_num = 2;
				break;
			case get_set_loc::Ss:				// Set: set
				red_var = get_set_loc::Set;
				del_state_num = 1;
				break;
			case get_set_loc::sss:			// set : set set
				red_var = get_set_loc::set;
				del_state_num = 2;
				break;
			case get_set_loc::sc :			// set : c
				s += chars.top();
				chars.pop();
				red_var = get_set_loc::set;
				del_state_num = 1;
				break;
			case get_set_loc::sc_c :	{	// set : c - c
				char high = chars.top();
				chars.pop();
				char low = chars.top();
				chars.pop();
				if( low > high || high > SCHAR_MAX)
					err = true;
				else {
					while( low <= high )
						s += low++;
				}
				red_var = get_set_loc::set;
				del_state_num = 3;
				break;	}
			default :
				break;
			}
			while(del_state_num-- > 0 )
				states.pop();
			states.push(gotos[states.top()][red_var]);
		}
	}
	if( err ) {
		while( token.get() != END )
			;
		s.clear();
		return ERROR;
	} else {
		return OK;
	}
}

bool build_dfa_tree_loc::rev_set(mylib::Set<char> &s, size_t max) {	// 127= max
	mylib::Set<char> t;
	for( char c=0;(size_t) c <= max; c++ ) {
		if( !s.exist(c) )		// not exist
			t += c;				// add it
	}
	s = t;
	return get_set_loc::OK;
}
#endif
